package com.beiding.dao;

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.Assert;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public interface CommonOperations<T> {

    /**
     * 使用Id查找,并且限定字段
     * @param id        查找的字段
     * @param fields    限定的字段
     * @return
     */
    default Optional<T> findByIdLimitFields(String id, List<String> fields) {
        Assert.notNull(id,"_id"+"不能为null");
        Document q = new Document();
        q.put("_id", id);
        Document f = new Document();
        fields.forEach(
                it -> f.put(it, true)
        );
        return Optional.ofNullable(mongoOperations().findOne(new BasicQuery(q, f), type()));
    }

    /**
     * 使用Id查找,并且限定字段
     * @param id        查找的字段
     * @param fields    限定的字段.如果未指定就显示全部字段
     */
    default Optional<T> findByIdLimitFields(String id,String... fields) {
        Assert.notNull(id,"_id"+"不能为null");
        if (fields.length == 0) {
            return Optional.ofNullable(mongoOperations().findOne(Query.query(Criteria.where("_id").is(id)), type()));
        } else return findByIdLimitFields(id, Arrays.asList(fields));
    }

    /**
     * 更新一个对象的部分字段
     * @param id    被更新字段的对象
     * @param fields    更新的字段
     */
    default void updateFields(String id, Document fields) {
        Assert.notNull(id,"_id"+"不能为null");
        Update update = new Update();
        fields.forEach(
                update::set
        );
        mongoOperations().updateFirst(Query.query(Criteria.where("_id").is(id)), update, type());
    }

    default void updateField(String id, String field, Object value) {
        Assert.notNull(id,"_id"+"不能为null");
        mongoOperations().updateFirst(Query.query(Criteria.where("_id").is(id)), Update.update(field, value), type());
    }

    /**
     * 判断指定列表中是否包含指定值.Redis判断两个值是否相等的依据是序列化的结果
     *
     * @param id        被操作对象
     * @param container 集合
     * @param value     值
     */

    default boolean containerContains(String id, String container, Object value) {
        return mongoOperations().exists(Query.query(Criteria.where("_id").is(id).and(container).is(value)), type());
    }


    /**
     * 向对象的列表中追加字段
     * @param id    备操作对象的Id
     * @param container 被追加字段的容器
     * @param value 被追加的值
     */
    default void containerAppend(String id, String container, Object... value)
    {
        //在更新之前首先判断是否具有该集合
        //创建一个空的集合
        if (!mongoOperations().exists(Query.query(Criteria.where("_id").is(id).and(container).exists(true)), type())) {
            updateField(id, container, Collections.emptyList());
        }

        Update update = new Update();
        for (Object o:value)
        {
            mongoOperations().updateFirst(Query.query(Criteria.where("_id").is(id)), update.push(container, o), type());
        }
    }

    /**
     * 从列表中移除所有值为value的元素
     * @param id    被操作对象的Id
     * @param container 被移除元素的容器
     * @param value     被移除的元素
     */
    default void containerRemove(String id, String container, Object... value)
    {
        Update update = new Update();
        update.pullAll(container, value);
        mongoOperations().updateFirst(Query.query(Criteria.where("_id").is(id)), update, type());
    }


    /**
     *
     * @return 参数T的Class对象
     */
    Class<T> type();

    /**
     *
     * @return MongoOperations的Bean对象
     */
    MongoOperations mongoOperations();

}
